import asyncio
import aiohttp
from loguru import logger
from proxypool.schemas import Proxy
from proxypool.storages.storages import StorageClient
from proxypool.settings import TEST_TIMEOUT, TEST_BATCH, TEST_URL, TEST_VALID_STATUS, TEST_ANONYMOUS
from aiohttp import ClientProxyConnectionError, ServerDisconnectedError, ClientOSError, ClientHttpProxyError
from asyncio import TimeoutError


EXCEPTIONS = (
    ClientProxyConnectionError,
    ConnectionRefusedError,
    TimeoutError,
    ServerDisconnectedError,
    ClientOSError,
    ClientHttpProxyError,
    AssertionError
)


class Tester(object):
    """
    检测代理模块
    """
    
    def __init__(self):
        """
        初始化客户端
        """
        self.sc = StorageClient()
    
    async def test(self, proxy: Proxy):
        """
        检测带库
        """
        async with aiohttp.ClientSession(connector=aiohttp.TCPConnector(ssl=False)) as session:
            try:
                logger.debug(f'检测 {proxy.string()}')
                # 当TEST_ANONYMOUS 为True时则使用代理
                if TEST_ANONYMOUS:
                    url = 'https://httpbin.org/ip'
                    async with session.get(url, timeout=TEST_TIMEOUT) as response:
                        resp_json = await response.json()
                        origin_ip = resp_json['origin']
                        # logger.warning(f'无当前代理，请求返回值：{resp_json}')
                    async with session.get(url, proxy=f'http://{proxy.string()}', timeout=TEST_TIMEOUT) as response:
                        resp_json = await response.json()
                        anonymous_ip = resp_json['origin']
                        logger.warning(f'当前代理ip{proxy.string()}，请求返回值：{resp_json}')
                    assert origin_ip != anonymous_ip
                    assert proxy.host == anonymous_ip
                async with session.get(TEST_URL, proxy=f'http://{proxy.string()}', timeout=TEST_TIMEOUT,
                                       allow_redirects=False) as response:
                    logger.warning(f'检测百度地址，状态：{response.status}')
                    if response.status in TEST_VALID_STATUS:
                        self.sc.max(proxy)
                        logger.debug(f'代理 {proxy.string()} 有效, 设置最大分数')
                    else:
                        self.sc.decrease(proxy)
                        logger.debug(f'代理 {proxy.string()} 失效，扣减分数')
            except EXCEPTIONS as e:
                self.sc.decrease(proxy)
                logger.error(f'代理error：{e}')
                logger.debug(f'代理 {proxy.string()} 失效，扣减分数')
    
    @logger.catch
    def run(self):
        """
        检测模块主方法
        """
        # event loop of aiohttp
        logger.info('开始检测...')
        count = self.sc.count()
        logger.debug(f'有{count} 个代理在运行')
        cursor = 0
        while True:
            logger.debug(f'检测游标从 {cursor}开始, 个数： {TEST_BATCH}')
            cursor, proxies = self.sc.batch(cursor, count=TEST_BATCH)
            if proxies:
                tasks = [self.test(proxy) for proxy in proxies]
                asyncio.run(asyncio.wait(tasks))
            if not cursor:
                break